layui.define(['jquery', 'element'], function(exports) {
  'use strict';

  var $ = layui.jquery;
  var element = layui.element;

  var MODULE_NAME = 'loading';

  function clamp(n, min, max) {
    if (n < min) {
      return min;
    } else if (n > max) {
      return max;
    } else {
      return n;
    }
  }

  function rgb(color) {
    if (!/^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/.test(color)) { return { r: 0, g: 0, b: 0 } }

    color = color.slice(1);

    if (color.length === 3) {
      color = color.split('');
      for (var i = 2; i >= 0; i--) {
        color.splice(i, 0, color[i]);
      }
      color = color.join('');
    }

    return {
      r: ~~('0x' + color.slice(0, 2)),
      g: ~~('0x' + color.slice(2, 4)),
      b: ~~('0x' + color.slice(4, 6))
    };
  }

  function rgba(color, opacity) {
    color = rgb(color);
    return 'rgba(' + [color.r, color.g, color.b, opacity].join(',') + ')';
  }

  function Loading() {
    this.percent = 0;
    this.state = 0; // 0: pause 1: loading
    this.layID = 'loading-' + (Math.random().toString(36).slice(4) + +new Date());
  }

  var config = Loading.config = {
    failedColor : '#FF5722',
    successColor: '#1E9FFF',
    parent      : 'body',
    height      : '2px',
    zIndex      : 3000
  };

  Loading.prototype.configure = function(options) {
    if ($.type(options) !== 'object') return;

    var key, value;
    for (key in options) {
      value = options[key];
      if (value != null && options['hasOwnProperty'](key)) {
        config[key] = value;
      }
    }
  };

  Loading.prototype.render = function() {
    var $parent = $(config.parent);
    var $progress = $parent.children('#' + this.layID);

    if ($progress.length <= 0) {
      $progress = $('<div id="' + this.layID + '" lay-filter="' + this.layID + '" class="layui-progress"><div class="layui-progress-bar" lay-percent="0%"></div></div>');
      $progress.css({
        backgroundColor: 'transparent',
        height         : config.height,
        position       : 'fixed',
        top            : 0,
        right          : 0,
        left           : 0,
        zIndex         : config.zIndex,
        transition     : 'all 200ms ease'
      });
      $progress.children('.layui-progress-bar').css({
        backgroundColor: config.successColor,
        height         : config.height,
        boxShadow      : '0 0 5px ' + rgba(config.successColor, 0.6)
      });
      $parent.append($progress);
    }

    return $progress;
  };

  Loading.prototype.start = function() {
    if (this.state === 1) {
      this.set(10);
      return;
    }

    var _this = this;
    var $progress = this.render();

    $progress.css('opacity', 1);
    this.state = 1;
    this._timer && clearInterval(this._timer);
    this._timer = setInterval(function() {
      _this.increase();
    }, 200);
    return this;
  };

  Loading.prototype.random = function() {
    var num = 0;

    if (this.percent >= 0 && this.percent < 20) {
      num = Math.random() * 5;
    } else if (this.percent >= 20 && this.percent < 40) {
      num = Math.random() * 3;
    } else if (this.percent >= 40 && this.percent < 80) {
      num = Math.random() * 2;
    } else if (this.percent >= 80 && this.percent < 98) {
      num = Math.random();
    } else if (this.percent >= 98 && this.percent < 100) {
      num = Math.random() / 10;
    }

    return num;
  };

  Loading.prototype.set = function(num) {
    this.percent = num || 0;
    element.progress(this.layID, this.percent + '%');
    return this;
  };

  Loading.prototype.increase = function() {
    if (this.state) {
      this.percent += this.random();
      this.percent = clamp(this.percent, 0, 99.85);
      element.progress(this.layID, this.percent + '%');
    } else {
      this.start();
    }
    return this;
  };

  Loading.prototype.finish = function() {
    this.set(100);
    this.destory();
    return this;
  };

  Loading.prototype.pause = function() {
    clearInterval(this._timer);
    this.state = 0;
    return this;
  };

  Loading.prototype.destory = function() {
    var _this = this;
    var $progress = this.render();
    this.state = 0;
    clearInterval(this._timer);
    setTimeout(function() {
      $progress.css('opacity', 0);
      setTimeout(function() {
        _this.set(0);
        $progress.remove();
      }, 200);
    }, 300);
    return this;
  };

  Loading.prototype.failed = function() {
    $('#' + this.layID).children('.layui-progress-bar').css({
      backgroundColor: config.failedColor,
      boxShadow      : '0 0 5px ' + rgba(config.failedColor, 0.6)
    });
    return this.finish();
  };

  exports(MODULE_NAME, new Loading());
});
